#pragma once

#include <iostream>
#include<string>
#include<cstring>
#include<cerrno>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"err.hpp"


namespace nt_client
{
    class UdpClient
    {
    public:
        // 构造
        UdpClient(const std::string& ip,uint16_t port)
        :server_ip_(ip),server_port_(port) 
        {} 
        // 析构
        ~UdpClient() 
        {} 

        // 初始化客户端
        void InitClient() 
        {
            // 1. 创建套接字
            sock_ = socket(AF_INET,SOCK_DGRAM,0);

            if(sock_ == -1)
            {
                std::cout << "Create Socket Fail: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }

            std::cout << "Create Success Socket: " << sock_ << std::endl;

            // 2.构建服务器的 sockaddr_in 结构体信息
            bzero(&svr_,sizeof(svr_));
            svr_.sin_family = AF_INET; //设置为网络通信
            svr_.sin_addr.s_addr = inet_addr(server_ip_.c_str()); // 绑定服务
            svr_.sin_port = htons(server_port_); //绑定服务器端口号


        }

        // 启动客户端
        void StartClient() 
        {
            char buff[1024];

            while(true)
            {
                // 1. 发送消息
                std::string msg;
                std::cout<<"Input Message#: ";
                std::getline(std::cin,msg);

                ssize_t n =sendto(sock_,msg.c_str(),msg.size(),0,(const struct sockaddr*)&svr_,sizeof(svr_));

                if(n == -1)
                {
                    std::cout << "Send Message Fail: " << strerror(errno) << std::endl;
            continue; // 重新输入消息并发送
                }

                // 2. 接收消息
                socklen_t len =sizeof(svr_); //创建一个变量，因为接下来的参数需要传入左值
                n = recvfrom(sock_,buff,sizeof(buff)-1,0,(struct sockaddr*)&svr_,&len);

                if(n > 0)
                {
                    buff[n] = '\0';
                }
                else
                continue;

                // 可以再次获取ip地址于端口号
                std::string ip = inet_ntoa(svr_.sin_addr);
                uint16_t port = ntohs(svr_.sin_port);

                printf("Client get message from [%s:%d]# %s\n",ip.c_str(), port, buff);
            }
        }

    private:
        std::string server_ip_; //服务器ip地址
        uint16_t server_port_; //服务器端口号
        int sock_; //客户端套接字
        struct sockaddr_in svr_; //服务器的sockaddr_in结构体信息
    };
}
